﻿using Sidvall.Data;
using Sidvall.Serialization;

namespace Sidvall.Security
{
    public class ServerContent
    {
        #region Public Members

        /// <summary>
        /// Loaded from Sidvall.SystemContext.Current.AuthorizationManager (AuthorizationManager)
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public ResourceItemCollection ResourceItems { get; set; }
        /// <summary>
        /// Loaded from Sidvall.SystemContext.Current.UserManager (AuthorizationManager)
        /// </summary>
        public UserItem UserItem { get; set; }
        /// <summary>
        ///  Loaded from Identity provider (SecurityManager, Facebook, etc)
        /// </summary>
        public UserInfo UserInfo { get; set; }
        /// <summary>
        /// Custom values
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public ParameterCollection Parameters { get; set; }

        #region UserName

        public string UserName
        {
            get
            {
                string value;
                if (this.UserInfo != null)
                {
                    value = this.UserInfo.GetName();
                    if (!string.IsNullOrWhiteSpace(value))
                        return value;
                    value = this.UserInfo.GetEmail();
                    if (!string.IsNullOrWhiteSpace(value))
                        return value;
                    if (!string.IsNullOrWhiteSpace(this.UserInfo.Sub))
                        return this.UserInfo.Sub;
                }
                if (this.UserItem != null)
                {
                    if (!string.IsNullOrWhiteSpace(this.UserItem.Name))
                        return this.UserItem.Name;
                }
                return string.Empty;
            }
        }

        #endregion
        #region UserStatus

        public IdentityStatus UserStatus
        {
            get
            {
                if (this.UserItem == null)
                    return Sidvall.Security.IdentityStatus.Invalid;
                return this.UserItem.UserStatus;
            }
        }

        #endregion
        #region UserStatusReasonPhrase

        public string UserStatusReasonPhrase
        {
            get
            {
                return this.UserItem?.UserStatusReasonPhrase;
            }
        }

        #endregion

        #region ContainsResourceItem

        public bool ContainsResourceItem(string resource)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAny(resource);
        }
        public bool ContainsResourceItem(string resource, string action)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAny(resource, action);
        }
        public bool ContainsResourceItem(string resource, string action, string subAction)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAny(resource, action, subAction);
        }

        #endregion
        #region ContainsResourceItemWithExactMatch

        public bool ContainsResourceItemWithExactMatch(string resource)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAnyWithExactMatch(resource);
        }
        public bool ContainsResourceItemWithExactMatch(string resource, string action)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAnyWithExactMatch(resource, action);
        }
        public bool ContainsResourceItemWithExactMatch(string resource, string action, string subAction)
        {
            if (this.ResourceItems == null)
                return false;
            return this.ResourceItems.ContainsAnyWithExactMatch(resource, action, subAction);
        }

        #endregion
        #region GetParameterValue

        public T GetParameterValue<T>(string key)
        {
            var item = this.ObjectParameters.FindObjectParameter(key);
            if (item == null)
            {
                lock (_Mutex)
                {
                    item = this.ObjectParameters.FindObjectParameter(key);
                    if (item == null)
                    {
                        var value = this.Parameters.ValueToObject<T>(key, default(T));
                        this.ObjectParameters.Add(key, value);
                        return value;
                    }
                }
            }
            return (T)item.Value;
        }

        #endregion
        #region SetParameterValue

        public void SetParameterValue(string key, object value)
        {
            lock (_Mutex)
            {
                this.ObjectParameters.AddOrUpdate(key, value);
            }
        }

        #endregion

        #endregion
        #region Private Members

        private readonly object _Mutex = new object();

        #region ObjectParameters

        private System.Lazy<ObjectParameterCollection> _ObjectParameters = new System.Lazy<ObjectParameterCollection>();
        private ObjectParameterCollection ObjectParameters
        {
            get
            {
                return _ObjectParameters.Value;
            }
        }

        #endregion

        #endregion
    }
}
